#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "aceMesh_runtime_c.h"
#include "matmul_aceMesh.h"
#include "slave.h"
__thread_local_fix int i,j,k,s_starti,s_endi,s_startj,s_endj,s_startk,s_endk,s_TS;
__thread_local volatile unsigned long get_reply,put_reply;
#if (_TS*_TS*3*8/1024<64)
__thread_local double s_A[_TS][_TS];
__thread_local double s_B[_TS][_TS];
__thread_local double s_C[_TS][_TS];
#else
#define TASK_FLOW
__thread_local double s_A[TASK_BSIZE_1][TASK_BSIZE_1];
__thread_local double s_B[TASK_BSIZE_1][TASK_BSIZE_1];
__thread_local double s_C[TASK_BSIZE_1][TASK_BSIZE_1];
__thread_local int ii,jj,kk;
#endif
extern double A[_N/_TS][_M/_TS][_TS][_TS];
extern double B[_M/_TS][_P/_TS][_TS][_TS];
extern double C[_N/_TS][_P/_TS][_TS][_TS];

void stencil_core(targs *args){
   s_TS=args->TS;
   s_starti=args->starti;
   s_startj=args->startj;
   s_startk=args->startk;
#ifdef MMEM   
   for ( i = 0; i < s_TS; i++) {
      for (j= 0; j < s_TS; j++) {
         for (k = 0; k < s_TS; k++) {
            C[s_starti][s_startj][i][j] += A[s_starti][s_startk][i][k] * B[s_startk][s_startj][k][j];
         }
      }
    }
#else
#ifdef TASK_FLOW
    int tsize, bsize, stride;
    for(ii=0;ii<s_TS;ii+=TASK_BSIZE_1){
        for(jj=0;jj<s_TS;jj+=TASK_BSIZE_1){
            bsize=TASK_BSIZE_1*8;
            stride=(s_TS-TASK_BSIZE_1)*8;
            tsize=TASK_BSIZE_1*bsize;
            get_reply=0;
            athread_get(PE_MODE,&C[s_starti][s_startj][ii][jj]
                        , &s_C[0][0]
                        , tsize, (void*)&get_reply
                        , 0,stride,bsize);
            while(get_reply!=1);
            for(kk=0;kk<s_TS;kk+=TASK_BSIZE_1){
            get_reply=0;
            athread_get(PE_MODE,&A[s_starti][s_startk][ii][kk]
                        , &s_A[0][0]
                        , tsize, (void*)&get_reply
                        , 0,stride,bsize);
            athread_get(PE_MODE,&B[s_startk][s_startj][kk][jj]
                        , &s_B[0][0]
                        , tsize, (void*)&get_reply
                        , 0,stride,bsize);
           
            while(get_reply!=2);
            for ( i = 0; i < TASK_BSIZE_1; i++) {
                for (j= 0; j < TASK_BSIZE_1; j++) {
                    for (k = 0; k < TASK_BSIZE_1; k++) {
                        s_C[i][j] += s_A[i][k] * s_B[k][j];
                    }
                }
            }
            }
            put_reply=0;
            athread_put(PE_MODE,&s_C[0][0]
                       ,&C[s_starti][s_startj][ii][jj]
                       ,tsize,(void*)&put_reply
                       ,stride,bsize);           
            while(put_reply!=1);
        }
    }
#else
    get_reply=0;
    athread_get(PE_MODE,&A[s_starti][s_startk][0][0]
               , &s_A[0][0]
               , s_TS*s_TS*8, (void*)&get_reply
               , 0,0,0);
    athread_get(PE_MODE,&B[s_startk][s_startj][0][0]
               , &s_B[0][0]
               , s_TS*s_TS*8, (void*)&get_reply
               , 0,0,0);
    athread_get(PE_MODE,&C[s_starti][s_startj][0][0]
               , &s_C[0][0]
               , s_TS*s_TS*8, (void*)&get_reply
               , 0,0,0);
    while(get_reply!=3);
    for ( i = 0; i < s_TS; i++) {
      for (j= 0; j < s_TS; j++) {
         for (k = 0; k < s_TS; k++) {
            s_C[i][j] += s_A[i][k] * s_B[k][j];
         }
      }
    }
    put_reply=0;
    athread_put(PE_MODE,&s_C[0][0]
               ,&C[s_starti][s_startj][0][0]
               ,s_TS*s_TS*8,(void*)&put_reply
               ,0,0);           
    while(put_reply!=1);
#endif
#endif


}